package gbm

import (
	"fmt"
	"reflect"
	"strings"

	"sort"

	"github.com/spf13/cast"
)

// SliceToString 将字符串切片转换为单个字符串。
// 参数:
//
//	ls: 字符串切片，包含需要转换的字符串元素。
//	sep: 拼接符，用于连接切片中的字符串元素，可以是空格、下划线、@等。
//
// 返回值:
//
//	返回一个字符串，该字符串是通过使用拼接符连接切片中的所有元素而生成的。
func SliceToString(ls []string, sep string) string {
	var result string
	for index, i := range ls {
		if index == 0 {
			// 对于切片中的第一个元素，直接赋值给result。
			result = cast.ToString(i)
		} else {
			// 对于切片中的后续元素，使用拼接符与result进行拼接。
			result = result + sep + cast.ToString(i)
		}
	}
	return result
}

// SliceToSlice 将切片元素切割整合到一个切片中
// 该函数接收一个字符串切片text和一个分隔符sep作为参数
// 它会遍历text中的每个字符串，使用sep进行分割，并将分割后的结果整合到一个新的切片中返回
// 如果text为空，则直接返回空切片
func SliceToSlice(text []string, sep string) []string {
	// 初始化结果切片
	var result []string

	// 检查text是否为空，如果非空则进行处理
	if len(text) > 0 {
		// 遍历text中的每个字符串
		for _, s := range text {
			// 使用分隔符sep对字符串s进行分割
			tmp := strings.Split(s, sep)

			// 如果分割后的切片长度大于1，则将所有元素添加到结果切片中
			if len(tmp) > 1 {
				result = append(result, tmp...) // 在切片尾部添加元素
			} else {
				// 如果分割后的切片长度不大于1，则直接添加原字符串到结果切片中
				result = append(result, s) // 在切片尾部添加元素
			}
		}
		// 返回处理后的结果切片
		return result
	}
	// 如果text为空，直接返回空切片
	return text
}

// SliceSort 对字符串切片进行排序。
// 该函数接收一个字符串切片作为参数，并使用sort包的Strings函数对其进行排序。
// 排序后，原切片的内容将按照字典序进行重新排列。
func SliceSort(ls []string) {
	sort.Strings(ls)
}

// SliceRemoveNull 移除字符串切片中的空字符串元素。
// 遍历给定的字符串切片，排除掉空字符串或仅包含空格的字符串，返回一个新的切片。
// 参数 l: 输入的字符串切片。
// 返回值: 一个新的字符串切片，其中不包含空字符串或仅包含空格的字符串。
func SliceRemoveNull(l []string) []string {
	// 初始化一个空的字符串切片，用于存储非空字符串。
	var tmp []string

	// 遍历输入的字符串切片。
	for _, value := range l {
		// 检查当前元素是否为空字符串或仅包含空格的字符串。
		if value == "" || value == " " || len(value) == 0 {
			// 如果是空字符串或仅包含空格的字符串，则跳过当前循环的剩余部分，继续下一次循环。
			continue
		}
		// 如果当前元素不是空字符串，则将其添加到临时切片中。
		tmp = append(tmp, value)
	}

	// 返回临时切片，其中不包含任何空字符串或仅包含空格的字符串。
	return tmp
}

// SliceMerge 合并两个字符串切片
// 参数:
//
//	l: 第一个字符串切片
//	r: 第二个字符串切片
//
// 返回值:
//
//	合并后的字符串切片
//
// 该函数通过将第二个切片追加到第一个切片的末尾来实现切片的合并
func SliceMerge(l, r []string) []string {
	// 将切片 l 和 r 进行合并，并将结果存储在临时切片 tmp 中
	tmp := append(l, r...)
	// 返回合并后的切片 tmp
	return tmp
}

// SliceReplace 替换切片中的元素
// 该函数遍历切片 l，当遇到需要替换的元素 replace 时，将其替换为切片 r 中的所有元素
// 参数:
//
//	l: 原始字符串切片
//	r: 用于替换的字符串切片
//	replace: 需要被替换的字符串
//
// 返回值:
//
//	返回一个新的字符串切片，其中所有的 replace 都被替换为 r 中的元素
func SliceReplace(l, r []string, replace string) []string {
	// 初始化一个空的字符串切片用于存储结果
	var tmp []string
	// 遍历原始切片 l
	for _, value := range l {
		// 当当前元素等于需要替换的元素 replace 时
		if value == replace {
			// 将 r 中的所有元素添加到结果切片中
			tmp = append(tmp, r...)
		} else {
			// 否则，将当前元素添加到结果切片中
			tmp = append(tmp, value)
		}
	}
	// 返回构建好的结果切片
	return tmp
}

// SliceRemove 移除切片中的元素
// 参数 l: 原始字符串切片
// 参数 remove: 需要移除的字符串切片
// 返回值: 移除元素后的字符串切片
func SliceRemove(l, remove []string) []string {
	// 初始化一个空的字符串切片用于存储结果
	var tmp []string
	// 遍历原始字符串切片
	for _, value := range l {
		// 检查当前元素是否为空字符串、单空格或双空格，如果是则跳过
		if !(value == "" || value == " " || value == "  ") {
			// 将非移除条件的元素添加到结果切片中
			tmp = append(tmp, value)
		}
	}
	// 返回结果切片
	return tmp
}

// SliceRemoveValue 从字符串切片中移除所有与指定值相同的元素
// 参数:
//
//	l: 待处理的字符串切片
//	values: 需要移除的值
//
// 返回值:
//
//	移除指定值后的字符串切片
func SliceRemoveValue(l []string, values string) []string {
	// 遍历字符串切片，寻找与指定值相同的元素
	for index, value := range l {
		// 当找到与指定值相同的元素时，从切片中移除它
		if value == values {
			// 删除字符数量0的元素
			l = append(l[:index], l[index+1:]...)
		}
	}
	// 返回移除指定值后的字符串切片
	return l
}

// SliceRemoveIndex 从一个字符串切片中删除指定索引的元素。
// 参数:
//
//	l: 要从中删除元素的字符串切片。
//	index: 要删除的元素的索引。
//
// 返回值:
//
//	[]string: 删除指定索引元素后的切片。
//	error: 如果索引超出切片范围，则返回错误。
func SliceRemoveIndex(l []string, index int) ([]string, error) {
	// 检查索引是否在切片长度范围内
	if len(l) > index {
		// 通过切片操作删除指定索引的元素
		l = append(l[:index], l[index+1:]...)
		return l, nil
	}
	// 如果索引超出范围，输出切片长度和给定索引以供调试，并返回错误
	fmt.Println(len(l))
	fmt.Println(index)
	return l, fmt.Errorf("索引值大于实际值")
}

// SliceInAny 检查一个任意类型的值是否存在于一个任意类型的切片中。
// 参数v是待查找的值，参数s是待搜索的切片。
// 该函数使用反射来比较元素，因为v和s的类型都是any，这允许函数处理不同类型的值和切片。
// 如果找到v存在于s中，则返回true，否则返回false。
func SliceInAny(v any, s []any) bool {
	// 遍历切片s中的每个元素。
	for i := 0; i < len(s); i++ {
		// 使用reflect.DeepEqual比较两个值是否相等，这可以处理任意类型的比较。
		if reflect.DeepEqual(s[i], v) {
			// 如果找到相等的元素，返回true。
			return true
		}
	}
	// 如果遍历完切片后没有找到相等的元素，返回false。
	return false
}

// SliceInInt 判断一个元素是否存在于一个切片中
func SliceInInt(v int, s []int) bool {
	for i := 0; i < len(s); i++ {
		if reflect.DeepEqual(s[i], v) {
			return true
		}
	}
	return false
}

// SliceInStr 判断一个元素是否存在于一个切片中
// 参数:
//
//	v: 待查找的元素
//	s: 待搜索的切片
//
// 返回值:
//
//	bool: 如果元素存在于切片中，则返回true；否则返回false
func SliceInStr(v string, s []string) bool {
	// 遍历切片中的每个元素
	for i := 0; i < len(s); i++ {
		// 使用reflect.DeepEqual比较元素，以处理可能的深度比较需求
		if reflect.DeepEqual(s[i], v) {
			// 如果找到元素，立即返回true
			return true
		}
	}
	// 如果遍历结束仍未找到元素，返回false
	return false
}

// SliceInByte 判断一个元素是否存在于一个切片中
// 参数:
//
//	v byte: 待查找的元素
//	s []byte: 待搜索的切片
//
// 返回值:
//
//	bool: 如果元素存在于切片中，则返回true；否则返回false
func SliceInByte(v byte, s []byte) bool {
	// 遍历切片中的每个元素
	for i := 0; i < len(s); i++ {
		// 使用reflect.DeepEqual比较元素，以处理可能的值相等但类型不等的情况
		if reflect.DeepEqual(s[i], v) {
			// 如果找到元素，返回true
			return true
		}
	}
	// 如果遍历完切片后仍未找到元素，返回false
	return false
}

// SliceStrReduction 对切片进行去重操作
// 参数 s: 待去重的字符串切片
// 返回值: 去重后的字符串切片
func SliceStrReduction(s []string) []string {
	// 初始化一个空的字符串切片用于存储去重后的结果
	var tmp []string
	// 遍历输入的字符串切片
	for _, v := range s {
		// 如果当前元素不在结果切片中，则将其添加到结果切片中
		if !SliceInStr(v, tmp) {
			tmp = append(tmp, v)
		}
	}
	// 返回去重后的字符串切片
	return tmp
}
